/*
    $Id$
    MAR another horizontal scroll action game
    Copyright (C) 2009 Japan Manoretimedia Lab.

    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation; either version 2 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program; if not, write to the Free Software
    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
*/

#include "main.h"
#include <assert.h>
#include "graphics.h"
#include "input.h"
#include "util.h"
#include "script.h"
#include "collision.h"

struct Main {
    HINSTANCE hInst;
    HWND      hWnd;
    WH        clientWH;
};

Main *
Main_Instance(void)
{
    static Main self;

    return &self;
}

HINSTANCE
Main_GetHInstance(Main *self)
{
    assert(self);

    return self->hInst;
}

HWND
Main_GetHWnd(Main *self)
{
    return self->hWnd;
}

static HRESULT
Main_Init(Main *self)
{
    HRESULT hr;

    assert(self);

    IFR(GR_Init(GR_Instance(), self->hWnd, self->clientWH));
    IFR(IN_Init(IN_Instance(), self->hInst, self->hWnd));
    Collision_Init(Collision_Instance());

    Script_Init(Script_Instance());
    Script_Load(Script_Instance(), "script/script.lua");
    Script_PCall(Script_Instance(), "Init");

    return hr;
}

static void
Main_Term(Main *self)
{
    assert(self);

    Script_PCall(Script_Instance(), "Term");
    Script_Term(Script_Instance());

    Collision_Term(Collision_Instance());
    IN_Term(IN_Instance());
    GR_Term(GR_Instance());
}

static HRESULT
Main_FrameMove(Main *self)
{
    HRESULT hr;
    (void)self;

    IFR(IN_FrameMove(IN_Instance()));

    Script_PCall(Script_Instance(), "Update");
    Collision_Update(Collision_Instance());
    
    return hr;
}

static HRESULT
Main_Render(Main *self)
{
    HRESULT hr;
    (void)self;

    IFR(GR_Render(GR_Instance()));
    return hr;
}

static HRESULT
Main_MessageLoop(Main *self)
{
    HRESULT hr = S_OK;
    MSG msg;

    (void)self;

    do {
        BOOL bRv = PeekMessage(&msg, NULL, 0U, 0U, PM_REMOVE);
        if (bRv) {
            TranslateMessage(&msg);
            DispatchMessage(&msg);
            continue;
        }

        IFR(Main_FrameMove(self));
        IFR(Main_Render(self));
    } while (msg.message != WM_QUIT);

    DebugPrintf(L"%S WM_QUIT received\n", __FUNCTION__);
    return hr;
}

static HRESULT
Main_Run(Main *self)
{
    HRESULT hr;

    assert(self);

    IFMB(Main_Init(self));
    if (SUCCEEDED(hr)) {
        ShowWindow(self->hWnd, SW_SHOWDEFAULT);
        UpdateWindow(self->hWnd);

        IFMB(Main_MessageLoop(self));
    }

    Main_Term(self);

    return hr;
}

static LRESULT WINAPI
MsgProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
    Main *self = Main_Instance();

    assert(self);

    switch (msg) {
    case WM_DESTROY:
        PostQuitMessage(0);
        return 0;
    }

    return DefWindowProc(hWnd, msg, wParam, lParam);
}

INT WINAPI
wWinMain(HINSTANCE hInst, HINSTANCE, LPWSTR, INT)
{
    Main *self = Main_Instance();
    self->hInst = hInst;

    WNDCLASSEX wc = {
        sizeof(WNDCLASSEX), CS_CLASSDC, MsgProc, 0L, 0L,
        self->hInst, NULL, NULL, NULL, NULL,
        Title(), NULL
    };
    RegisterClassEx(&wc);

    self->hWnd = CreateWindow(Title(), Title(), WS_OVERLAPPEDWINDOW,
        100, 100,
        WINDOW_W + GetSystemMetrics(SM_CXFRAME) * 2,
        WINDOW_H + GetSystemMetrics(SM_CYCAPTION) + (GetSystemMetrics(SM_CXFRAME)) * 2,
        NULL, NULL, self->hInst, NULL);

    self->clientWH = WH(WINDOW_W, WINDOW_H);

    Main_Run(self);

    UnregisterClass(Title(), self->hInst);
    return 0;
}
